/*
 * Copyright (c) 2010 Mathew Hall, University of Sheffield.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided
 * with the distribution.
 *
 * Neither the name of the University of Sheffield nor the names of its
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
package search.genes;

import static gpinterpreter.vector.VecSymbol.MOVE;
import static gpinterpreter.vector.VecSymbol.NOP;
import gpinterpreter.vector.VecInstruction;
import gpinterpreter.vector.VecSymbol;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jgap.Configuration;
import org.jgap.Gene;
import org.jgap.InvalidConfigurationException;
import org.jgap.impl.IntegerGene;

/**
 * Represents an instruction as an integer, using bit twiddling to turn it into
 * an VecInstruction. For now at least subclassing IntegerGene fails on JGAP 3.5 so
 * use an IntegerGene as your Chromosome then the static method to turn it into
 * an instruction for GPInterpreter.
 */
public class IntegerInstructionGene extends IntegerGene implements
		InstructionGene {

	public int graphSize;
	private static VecSymbol[] symbols = {MOVE, /* SPLIT, */ NOP // ,MERGE
	};

	protected Gene newGeneInternal() {
		try {
			IntegerInstructionGene result = new IntegerInstructionGene(getConfiguration());
			result.setGraphSize(graphSize);
			return result;
		} catch (InvalidConfigurationException iex) {
			throw new IllegalStateException(iex.getMessage());
		}
	}

	public void setGraphSize(int s) {
		graphSize = s;
	}

	public int getGraphSize() {
		return graphSize;
	}

	public InstructionGene clone() {
		IntegerInstructionGene ig;
		try {
			ig = new IntegerInstructionGene(this.getConfiguration());
		} catch (InvalidConfigurationException ex) {
			Logger.getLogger(IntegerInstructionGene.class.getName()).log(Level.SEVERE, null, ex);
			throw new RuntimeException("Attempt to clone an IntegerInstructionGene failed.");
		}
		ig.setGraphSize(graphSize);
		ig.setAllele(new Integer(intValue()));
		return ig;
	}
	
	public IntegerInstructionGene(Configuration a_config, int size) throws InvalidConfigurationException{
		this(a_config);
		graphSize = size;
	}

	public IntegerInstructionGene(Configuration a_config)
			throws InvalidConfigurationException {
		super(a_config);

	}
	private static final long serialVersionUID = 1L;

	private static VecSymbol getSymbol(int val) {

		int instruction = val >>> 30;

		switch (instruction) {
			case 0:
			case 1:
				return MOVE;
			// break;
			case 2:
			case 3:
			default:
				return NOP;
			// break;
		}

	}

	/**
	 * Decode the Integer representation to an executable VecInstruction.
	 */
	public static VecInstruction getInstruction(int val, int graphSize) {

		VecSymbol operator = getSymbol(val);

		int lower = val & 0x7FFF;
		int higher = (val >>> 15) & 0x7FFF;

		lower = (lower % (graphSize)) + 1;
		higher = (higher % (graphSize)) + 1;

		return new VecInstruction(operator, lower, higher, -1);

	}

	public VecInstruction getInstruction() {

		return getInstruction(intValue(), graphSize);
	}

	public String toString() {
		return getInstruction().toString();
	}
}
